package com.justgame.project.base.servcice;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.github.yulichang.base.MPJBaseService;
import com.justgame.project.cloud.base.entity.BaseEntity;
import com.justgame.project.cloud.base.entity.BaseTable;
import com.justgame.project.cloud.common.exception.Exc;
import com.justgame.project.cloud.common.query.AbstractQueryWrapper;
import com.justgame.project.cloud.common.util.AssertKit;
import com.justgame.project.cloud.common.util.ObjUtil;
import com.justgame.project.cloud.common.util.ShiroUtils;
import lombok.NonNull;
import lombok.SneakyThrows;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

@SuppressWarnings("all")
public interface IBasicService<QW extends AbstractQueryWrapper<T,?,DTO>, T extends BaseTable, DTO> extends MPJBaseService<T> {
    @SneakyThrows
    default T requireGetById(Serializable id, String errorMessage){
        return Optional.ofNullable(getById(id)).orElseThrow(()->new Exc(errorMessage));
    }

    default boolean requireRemoveById(Serializable id,String errorMessage){
        if (!ShiroUtils.isAdmin()){
            T ent = getById(id);
            if (ent instanceof BaseEntity){
                AssertKit.isEquals(((BaseEntity)ent).getCreateUser(),ShiroUtils.getUserId(),errorMessage);
            }
        }
        return removeById(id);
    }

    default Integer selectJoinCount(QW queryWrapper) {
        return selectJoinCount(queryWrapper.build());
    }

    default DTO selectJoinOne(QW queryWrapper) {
        return selectJoinOne(queryWrapper.getDtoClass(),queryWrapper.build());
    }

    default List<DTO> selectJoinList(QW queryWrapper) {
        return selectJoinList(queryWrapper.getDtoClass(),queryWrapper.build());
    }

    default IPage<DTO> selectJoinListPage(QW queryWrapper) {
        return selectJoinListPage(queryWrapper.getPage(),queryWrapper.getDtoClass(),queryWrapper.build());
    }

    default Map<String, Object> selectJoinMap(QW queryWrapper) {
        return selectJoinMap(queryWrapper.build());
    }

    default List<Map<String, Object>> selectJoinMaps(QW queryWrapper) {
        return selectJoinMaps(queryWrapper.build());
    }

    default <P extends IPage<Map<String, Object>>> IPage<Map<String, Object>> selectJoinMapsPage(P page, QW queryWrapper) {
        return selectJoinMapsPage(page, queryWrapper.build());
    }

    default boolean save(@NonNull T entity) {
        AssertKit.notNull(entity,"数据异常");
        if (entity instanceof BaseEntity){
            if (((BaseEntity) entity).getCreateUser() == null) {
                try{
                    Long userId = ShiroUtils.getUserId();
                    ((BaseEntity) entity).setCreateUser(userId);
                }catch (Exception e){}
            }
            ((BaseEntity) entity).setCreateDate(LocalDateTime.now());
            ((BaseEntity) entity).setIsDel(false);
        }
        entity.setId(null);
        entity.setVersions(0);
        return SqlHelper.retBool(this.getBaseMapper().insert(entity));
    }

    default boolean delete(T entity) {
        AssertKit.isTrue(checkEntity(entity),"数据异常");
        if (!(entity instanceof BaseEntity)){
            return removeById(entity);
        }
        ((BaseEntity)entity).setIsDel(true);
        return updateById(entity);
    }

    default boolean updateById(T entity) {
        AssertKit.isTrue(checkEntity(entity),"数据异常");
        if (!(entity instanceof BaseEntity)){
            return SqlHelper.retBool(this.getBaseMapper().updateById(entity));
        }
        ((BaseEntity)entity).setUpdateDate(LocalDateTime.now());
        if (((BaseEntity)entity).getUpdateUser() == null) {
            Long userId = ShiroUtils.getUserId();
            ((BaseEntity)entity).setUpdateUser(userId);
        }
        return SqlHelper.retBool(this.getBaseMapper().updateById(entity));
    }

    default boolean checkEntity(T entity) {
        return Objects.nonNull(entity) && ObjUtil.checkId(entity);
    }

    /**
     * 确保数据的预期值在可控范围
     * @param t 预期值
     * @param defaultVal 阈值
     * @param <T> 返回一个基本可控的安全值
     * @return
     */
    default <T> T safeValue(T t,T defaultVal){
        return Optional.ofNullable(t).orElse(defaultVal);
    }

}
